﻿using Microsoft.Win32;
using SerialPortHelper.StrategyPattern;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace SerialPortHelper
{
    public partial class Form1 : Form
    {
        //是否打开
        private bool isOpen = false;

        //是否接受显示
        private bool isRxShow = true;

        //接收缓冲区
        private List<byte> reciveBuffer = new List<byte>();

        //发送缓冲区
        private List<byte> sendBuffer = new List<byte>();

        //接收计数
        private int reciveCount = 0;

        //发送计数
        private int sendCount = 0;

        //队列
        private Queue<byte> bufferQueue = null;

        //帧头标志
        private bool isHeadRecive = false;

        //帧长度
        private int frameLength = 0;

        //发送文件的内容
        private String strRead;

        //传输数据委托,将串口接收的数据发送到子窗体
        public TransmitData transmitData;

        //传输数据事件,将串口接收的数据发送到子窗体
        public event TransmitEventHandler transmitData2;

        //通过策略模式获取具体解析算法的对象
        public DecodedDataContext ddc;


        public Form1()
        {
            InitializeComponent();

            //跨线程检查设置为false,不做跨线程检查
            //Control.CheckForIllegalCrossThreadCalls = false;

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //c#支持的所 有字符
            //EncodingInfo[] encodingInfo = Encoding.GetEncodings();

            serialLoad();

            //实例化队列
            bufferQueue = new Queue<byte>();

            //Load时创建子窗体
            Form2 fr2 = new Form2();

            //接收数据委托窗体2 ReciveData 执行显示
            // transmitData += fr2.ReciveData; //委托形式

            //事件形式
            transmitData2 += new TransmitEventHandler(fr2.ReciveData2);

            //窗体2发送委托窗体1 sendBytes 执行发送
            //fr2.useForm1Send += sendBytes; //委托形式

            //事件形式
            fr2.useForm1Send2 += new TransmitEventHandler(sendBytes2);

            fr2.Show();

            //初始化通过策略模式获取具体解析算法的对象,这里使用简单解析数据帧
            ddc = new DecodedDataContext(new SimpleDecodedDataFrame());
            //如果后期使用Modbus解析,只需要换这里的实现类即可
            //ddc = new DecodedDataContext(new ModbusDecodedDataFrame());

        }

        /// <summary>
        /// 子窗体发送数据给串口
        /// </summary>
        /// <returns></returns>
        private void sendBytes(byte[] data)
        {
            serialPort1.Write(data, 0, data.Length);
            //发送计数器
            sendCount += data.Length;
            sendcount_tssl.Text = sendCount.ToString();
        }


        /// <summary>
        /// 子窗体发送数据给串口
        /// </summary>
        /// <returns></returns>
        private void sendBytes2(Object sender, TransmitEventArgs e)
        {
            serialPort1.Write(e.data, 0, e.data.Length);
            //发送计数器
            sendCount += e.data.Length;
            sendcount_tssl.Text = sendCount.ToString();
        }

        private void serialLoad()
        {
            //SerialPort获取串口
            //String [] ports=SerialPort.GetPortNames();
            //port_cbb.Items.AddRange(ports);

            //注册表中获取串口
            RegistryKey keyCom = Registry.LocalMachine.OpenSubKey(@"Hardware\DeviceMap\SerialComm");
            String[] sSubKeys = keyCom.GetValueNames();

            port_cbb.Items.Clear();
            foreach (var key in sSubKeys)
            {
                String portName = (string)keyCom.GetValue(key);
                port_cbb.Items.Add(portName);
            }


            port_cbb.SelectedIndex = 1; //串口
            baus_cbb.SelectedIndex = 1; //波特率
            check_cbb.SelectedIndex = 0; //校验位
            databit_cbb.SelectedIndex = 3;  //数据位
            stopbit_cbb.SelectedIndex = 0;//停止位
        }

        private void open_btn_Click(object sender, EventArgs e)
        {
            try
            {
                if (serialPort1.IsOpen == false)
                {
                    serialPort1.PortName = port_cbb.Text;
                    serialPort1.BaudRate = int.Parse(baus_cbb.Text);
                    serialPort1.DataBits = int.Parse(databit_cbb.Text);
                    switch (check_cbb.SelectedIndex)
                    {
                        //none,odd,even
                        case 0:
                            serialPort1.Parity = Parity.None;
                            break;
                        case 1:
                            serialPort1.Parity = Parity.Odd;
                            break;
                        case 2:
                            serialPort1.Parity = Parity.Even;
                            break;
                        default:
                            serialPort1.Parity = Parity.None;
                            break;
                    }

                    switch (stopbit_cbb.SelectedIndex)
                    {
                        // 1,1.5,2
                        case 0:
                            serialPort1.StopBits = StopBits.One;
                            break;
                        case 1:
                            serialPort1.StopBits = StopBits.OnePointFive;
                            break;
                        case 2:
                            serialPort1.StopBits = StopBits.Two;
                            break;

                        default:
                            serialPort1.StopBits = StopBits.One;
                            break;
                    }


                    serialPort1.Open();
                    isOpen = true;
                    open_btn.Text = "关闭串口";


                    //状态栏状态
                    state_tssl.Text = $"打开{serialPort1.PortName}串口成功!";

                }
                else
                {
                    serialPort1.Close();
                    isOpen = false;
                    open_btn.Text = "打开串口";

                    //状态栏状态
                    state_tssl.Text = $"关闭{serialPort1.PortName}串口成功!";
                }
            }
            catch (Exception ex)
            {
                //状态栏状态
                state_tssl.Text = $"打开{serialPort1.PortName}串口异常!";

                MessageBox.Show(ex.ToString() + serialPort1.PortName.ToString());
            }
        }

        private void sendData()
        {
            serialPort1.Write(sendBuffer.ToArray(), 0, sendBuffer.Count);

            //发送计数器
            sendCount += sendBuffer.Count;
            sendcount_tssl.Text = sendCount.ToString();

        }

        /// <summary>
        /// 发送按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void send_btn_Click(object sender, EventArgs e)
        {
            if (send_rtb.Text != "" && serialPort1.IsOpen)
            {
                Console.WriteLine(Transform.ToHexString(sendBuffer.ToArray()));
                sendData();
            }
            else
            {
                MessageBox.Show("请先输入发送数据!");
            }
        }

        /// <summary>
        /// 1.DataReceived事件他在辅助线程执行,在这里直接操作控件会出现跨线程非安全的检查
        /// 2.DataReceived事件他在辅助线程执行,数据更新到UI主线程时就已经跨线程了,可以使用异步线程来执行更新
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //如果暂停,则不接收数据
            if (isRxShow == false) return;

            #region 不考虑跨线程问题的接收方式
            //String dataRecive = serialPort1.ReadExisting();
            //receive_rtb.AppendText(dataRecive);
            //receive_rtb.AppendText(Environment.NewLine);
            #endregion

            //1.需要读取有效的数据BytesToRead
            byte[] dataTemp = new byte[serialPort1.BytesToRead];
            serialPort1.Read(dataTemp, 0, dataTemp.Length);
            reciveBuffer.AddRange(dataTemp);

            //接收到的长度
            reciveCount += dataTemp.Length;

            //调用委托,将串口接收的数据传输到子窗体中
            //transmitData?.Invoke(dataTemp);//(transmitData?.:transmitData不为空的时候调用,?.语法糖相当于 if(transmitData!=null){transmitData..Invoke(dataTemp);})

            //调用事件,将串口接收的数据传输到子窗体中
            /**
             *  使用 transmitData2?.Invoke 相当于以前调用事件的方式:
             *  if(transmitData2!=null)
             *  {
             *      transmitData2(this,new TransmitEventArgs {  data=dataTemp });
             *  }
             */
            //transmitData2?.Invoke(this, new TransmitEventArgs { data = dataTemp });


            this.Invoke(new EventHandler(delegate
            {
                //状态栏显示接收到的长度
                recivecount_tssl.Text = reciveCount.ToString();

                //如果未启用数据帧接收
                if (startData_chb.CheckState == CheckState.Unchecked)
                {
                    //字符串接收
                    if (!receivehex_chb.Checked)
                    {
                        // 2.编码格式的选择,两个串口或者和其他单片机程序通讯,要注意两边的编码格式需要一致
                        String str = Encoding.GetEncoding("gb2312").GetString(dataTemp);
                        // 3. winform中RichTextBox下,对于0x00会转成\0(\0代表结束符),不会直接显示
                        // 0x00 -> \0 
                        str = str.Replace("\0", "\\0"); //将 "\0" 转为 "\\0",通过转义字符显示出来

                        receive_rtb.AppendText(str);

                        //以上合并成一行
                        //receive_rtb.AppendText(Encoding.GetEncoding("gb2312").GetString(dataTemp).Replace("\0","\\0"));
                    }
                    else
                    {
                        //十六进制处理
                        receive_rtb.AppendText(Transform.ToHexString(dataTemp, " "));
                    }
                }
                else  //解析数据帧数据  用到队列 queue
                {
                    // 串口助手发送测试数据:7F0431323334DE1012(其中末尾12是脏数据)
                    //将dataTemp中所有的数据存到队列中
                    foreach (byte item in dataTemp)
                    {
                        //入列
                        bufferQueue.Enqueue(item);
                    }

                    // #if old的作用就是注释,因为没有old这种环境                    
#if old

                                        //解析获取帧头
                                        //如果没有帧头(判断队列中,是否从帧头开始,假设队列:{0x01,0x02,0x7F},我们就需要将0x7F移到最前面来,0x01,0x02是需要丢弃的)
                                        if (isHeadRecive == false)
                                        {
                                            foreach (byte item in bufferQueue.ToArray())
                                            {
                                                if (item != 0x7F)
                                                {
                                                    //将当前字节出列
                                                    bufferQueue.Dequeue();
                                                    Console.WriteLine("not 0x7F,Dequeue!!");
                                                }
                                                else
                                                {
                                                    // get 0X7F from bufferQueue
                                                    isHeadRecive = true;
                                                    Console.WriteLine("0x7F is recived!!");
                                                    break;
                                                }
                                            }
                                        }

                                        //如果是帧头
                                        if (isHeadRecive == true)
                                        {
                                            //判断有数据帧长度(有帧头0x7F(1字节)和长度(1字节))
                                            if (bufferQueue.Count >= 2)
                                            {
                                                Console.WriteLine(DateTime.Now.ToLongTimeString());

                                                Console.WriteLine($"show the data in bufferQueue:{Transform.ToHexString(bufferQueue.ToArray())}");

                                                //给帧长度赋值
                                                frameLength = bufferQueue.ToArray()[1];

                                                //数据的长度
                                                Console.WriteLine($"frame length={String.Format("{0:X2}", frameLength)}");

                                                //判断一帧完整的长度:(0x7F(1字节)+长度(1字节)+数据的长度frameLength(x字节)+CRC(2字节)),但是不代表数据是正确的
                                                if (bufferQueue.Count >= 1 + 1 + frameLength + 2)
                                                {
                                                    byte[] frameBuffer = new byte[1 + 1 + frameLength + 2];
                                                    Array.Copy(bufferQueue.ToArray(), 0, frameBuffer, 0, frameBuffer.Length);
                                                    //检查是否是有效数据
                                                    if (crc_check(frameBuffer))
                                                    {
                                                        Console.WriteLine("frame is check ok,pick it");
                                                        data_txb.Text = Transform.ToHexString(frameBuffer);
                                                        data1_txb.Text = String.Format("{0:X2}", frameBuffer[2]);
                                                        data2_txb.Text = String.Format("{0:X2}", frameBuffer[3]);
                                                        data3_txb.Text = String.Format("{0:X2}", frameBuffer[4]);
                                                        data4_txb.Text = String.Format("{0:X2}", frameBuffer[5]);
                                                    }
                                                    else
                                                    {
                                                        //无效数据
                                                        Console.WriteLine("bad frame,drop it.");
                                                    }

                                                    //不管是正确数据还是错误数据,都要将bufferQueue里的数据出列
                                                    for (int i = 0; i < 1 + 1 + frameLength + 2; i++)
                                                    {
                                                        bufferQueue.Dequeue();
                                                    }

                                                    //完成之后,将帧头标志设置为false,让其去处理下一帧的数据
                                                    isHeadRecive = false;

                                                }
                                                
                                            }
                                            //长度不对就继续接受数据

                                        }
#endif

                    #region 通过策略模式将解析数据帧操作和解析数据帧的算法分离
                    //获取帧数据(这部是算法的解析,交给了策略模式,以后换解析方法只需要实现DecodedData抽象类中的方法即可)
                    byte[] frameData = ddc.getDataFrames(bufferQueue);

                    //解析数据帧后的操作
                    if (frameData != null)
                    {
                        Console.WriteLine($"show the data in frameData:{Transform.ToHexString(frameData)}");

                        data_txb.Text = Transform.ToHexString(frameData);
                        data1_txb.Text = String.Format("{0:X2}", frameData[2]);
                        data2_txb.Text = String.Format("{0:X2}", frameData[3]);
                        data3_txb.Text = String.Format("{0:X2}", frameData[4]);
                        data4_txb.Text = String.Format("{0:X2}", frameData[5]);


                        for (int i = 0; i < frameData.Length; i++)
                        {
                            bufferQueue.Dequeue();
                        }

                    }
                    #endregion

                    /**
                     * 策略模式：一种定义一系列算法的方法，从概念上来看，所有这些算法完成的都是相同的工作，
                     * 只是实现方式不同，它可以以相同的方式调用所有的算法，减少了各种算法类和使用算法类之间的耦合。
                     */

                }


            }));
        }

        /// <summary>
        /// 数据校验
        /// </summary>
        /// <param name="frameBuffer"></param>
        /// <returns></returns>
        private bool crc_check(byte[] frameBuffer)
        {
            bool ret = false;

            //获取CRC之前的数据
            byte[] temp = new byte[frameBuffer.Length - 2];
            Array.Copy(frameBuffer, 0, temp, 0, temp.Length);
            //采用大端模式:DataCheck.BigOrLittle.BigEndian
            byte[] crcdata = DataCheck.DataCrc16_Ccitt(temp, DataCheck.BigOrLittle.BigEndian);

            if (crcdata[0] == frameBuffer[frameBuffer.Length - 2] && crcdata[1] == frameBuffer[frameBuffer.Length - 1])
            {
                //校验成功 check ok
                ret = true;
            }

            return ret;
        }

        /// <summary>
        /// 是否接收数据开关
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stop_btn_Click(object sender, EventArgs e)
        {
            if (isRxShow == true)
            {
                isRxShow = false;
                stop_btn.Text = "取消暂停";
            }
            else
            {
                isRxShow = true;
                stop_btn.Text = "暂停";
            }
        }

        /// <summary>
        /// 十六进制复选框状态改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void receivehex_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (receive_rtb.Text == "") return;

            //如果选择十六进制
            if (receivehex_chb.Checked)
            {
                receive_rtb.Text = Transform.ToHexString(reciveBuffer.ToArray(), " ");
            }
            else
            {
                receive_rtb.Text = Encoding.GetEncoding("gb2312").GetString(reciveBuffer.ToArray()).Replace("\0", "\\0");
            }
        }

        /// <summary>
        /// 接收手动清空
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void clear_btn_Click(object sender, EventArgs e)
        {
            reciveBuffer.Clear();
            //重置接收计数器
            reciveCount = 0;
            recivecount_tssl.Text = "0";
            receive_rtb.Text = "";
        }

        /// <summary>
        /// 自动清空
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void autoclear_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (autoclear_chb.Checked)
            {
                //开启定时器
                timer1.Start();

            }
            else
            {
                //停止定时器
                timer1.Stop();
            }
        }

        /// <summary>
        /// 定时器事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            //数据长度>=4096字节,则自动清空
            if (receive_rtb.Text.Length >= 4096)
            {
                reciveBuffer.Clear();
                //重置接收计数器
                reciveCount = 0;
                recivecount_tssl.Text = "0";
                receive_rtb.Text = "";
            }
        }

        /// <summary>
        /// 当焦点离开发送区时触发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void send_rtb_Leave(object sender, EventArgs e)
        {
            //十六进制选中时
            if (sendhex_chb.CheckState == CheckState.Checked)
            {
                //去掉空格后,检查是否是16进制的字符串
                if (DataEncoding.IsHexString(send_rtb.Text.Replace(" ", "")))
                {
                    sendBuffer.Clear();
                    sendBuffer.AddRange(Transform.ToBytes(send_rtb.Text.Replace(" ", "")));
                }
                else
                {
                    MessageBox.Show("请输入正确的十六进制数据!");
                    send_rtb.Select();//重新获得焦点
                }
            }
            else  //字符串
            {
                sendBuffer.Clear();
                sendBuffer.AddRange(Encoding.GetEncoding("gb2312").GetBytes(send_rtb.Text));
            }
        }

        /// <summary>
        /// 发送区文本改变时触发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void send_rtb_TextChanged(object sender, EventArgs e)
        {
            // 十六进制切换 会出现问题 这个问题就是0x00转换

        }

        /// <summary>
        /// 发送配置十六进制状态发生改变时触发
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sendhex_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (send_rtb.Text == "") return;

            //如果选中十六进制
            if (sendhex_chb.Checked == true)
            {
                send_rtb.Text = Transform.ToHexString(sendBuffer.ToArray(), " ");
            }
            else
            {
                send_rtb.Text = Encoding.GetEncoding("gb2312").GetString(sendBuffer.ToArray()).Replace("\0", "\\0");
            }

        }

        /// <summary>
        /// 清空发送
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sendclear_btn_Click(object sender, EventArgs e)
        {
            sendBuffer.Clear();
            send_rtb.Text = "";
            sendCount = 0;
            sendcount_tssl.Text = "0";
        }

        /// <summary>
        /// 自动发送
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void autosend_chb_CheckedChanged(object sender, EventArgs e)
        {
            //串口未打开且选中自动发送
            if (serialPort1.IsOpen == false && autosend_chb.CheckState == CheckState.Checked)
            {
                //取消选中
                //autosend_chb.Checked = false;
                autosend_chb.CheckState = CheckState.Unchecked;

                if (timer2 != null)
                {
                    timer2.Enabled = false;
                    timer2.Stop();
                }

                MessageBox.Show("发送失败,串口未打开!");
                return;
            }

            //串口打开且选中自动发送
            if (serialPort1.IsOpen && autosend_chb.CheckState == CheckState.Checked)
            {
                //禁用自动发送周期
                autotimer_txb.Enabled = false;
                //禁用手动发送
                send_btn.Enabled = false;

                int interval = Convert.ToInt32(autotimer_txb.Text);

                if (interval < 10 || interval > 60 * 1000)
                {
                    interval = 1000;
                    autotimer_txb.Text = "1000";
                    MessageBox.Show("自动发送数据的周期范围是10-60000毫秒", "警告");
                }

                timer2.Interval = interval;
                timer2.Start();
            }
            else  //关闭定时器和自动发送周期文本和手动发送按钮
            {
                //启用自动发送周期
                autotimer_txb.Enabled = true;
                //启用手动发送按钮
                send_btn.Enabled = true;

                if (timer2 != null)
                {
                    timer2.Stop();
                }

            }

        }

        /// <summary>
        /// 自动发送定时器事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer2_Tick(object sender, EventArgs e)
        {
            if (send_rtb.Text != "" && serialPort1.IsOpen)
            {
                Console.WriteLine(Transform.ToHexString(sendBuffer.ToArray()));
                sendData();
            }
            else
            {
                state_tssl.Text = "请先输入发送数据!";

                //这里定时器发送如果使用MessageBox会一直弹窗
                //MessageBox.Show("请先输入发送数据!");
            }
        }

        /// <summary>
        /// 清空计数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cleancount_tssl_Click(object sender, EventArgs e)
        {
            //清空发送
            sendBuffer.Clear();
            send_rtb.Text = "";
            sendCount = 0;
            sendcount_tssl.Text = "0";

            //清空接收
            reciveBuffer.Clear();
            receive_rtb.Text = "";
            reciveCount = 0;
            recivecount_tssl.Text = "0";
        }


        /// <summary>
        /// RTS
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RTS_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (RTS_chb.CheckState == CheckState.Checked)
            {
                serialPort1.RtsEnable = true;
            }
            else
            {
                serialPort1.RtsEnable = false;
            }
        }

        /// <summary>
        /// DTR
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DTR_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (DTR_chb.CheckState == CheckState.Checked)
            {
                serialPort1.DtrEnable = true;
            }
            else
            {
                serialPort1.DtrEnable = false;
            }
        }

        /// <summary>
        /// 选择路径
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void xzlj_btn_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fdDialog = new FolderBrowserDialog();
            //DialogResult.OK:路径选择完成
            if (fdDialog.ShowDialog() == DialogResult.OK)
            {
                //获取用户选择的路径
                recivefile_txb.Text = fdDialog.SelectedPath;

            }
        }

        /// <summary>
        /// 保存数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bcsj_btn_Click(object sender, EventArgs e)
        {
            if (receive_rtb.Text == "")
            {
                MessageBox.Show("保存失败,接收区没有数据!");
                return;
            }

            if (recivefile_txb.Text == "")
            {
                MessageBox.Show("请选择接收数据的保存的路径!");
                return;
            }

            String fileName = recivefile_txb.Text + "\\" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".txt";

            using (StreamWriter sw = new StreamWriter(fileName,false, Encoding.GetEncoding("gb2312")))
            {
                sw.Write(receive_rtb.Text);
                sw.Flush();
            }

            MessageBox.Show("保存成功!");
        }

        /// <summary>
        /// 打开文件(记载文本到发送区)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dkwj_btn_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofDialog = new OpenFileDialog();
            ofDialog.Title = "请选择文件";
            ofDialog.Filter = "文本文件(*.txt)|*.txt";
            //设置记录上次打开路径
            ofDialog.RestoreDirectory = true;

            if (ofDialog.ShowDialog() == DialogResult.OK)
            {
                String fileName = ofDialog.FileName;

                sendfile_txb.Text = fileName;

                using (StreamReader sr = new StreamReader(fileName, Encoding.GetEncoding("gb2312")))
                {
                    strRead = sr.ReadToEnd();
                    send_rtb.Text = strRead;
                }

            }

        }

        /// <summary>
        /// 发送文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void fswj_btn_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrWhiteSpace(strRead))
            {
                MessageBox.Show("请先选择文件!");
                return;
            }

            try
            {
                byte[] data = Encoding.GetEncoding("gb2312").GetBytes(strRead);
                sendCount += data.Length;
                sendcount_tssl.Text = sendCount.ToString();
                //做分页发送,每次只允许发送4096个字节(4KB),这是windows电脑上串口能发的最大数据
                //页数不不好剩余的字节数
                int pagenum = data.Length / 4096;
                //剩余的字节数
                int remaind = data.Length % 4096;

                //假设字节数为:8193,pagenum=2,则第一次为:(0*4906即0开始取4096个字节),第二次为:(1*4096即4096开始取4096个字节)
                for (int i = 0; i < pagenum; i++)
                {
                    serialPort1.Write(data, (i * 4096), 4096);
                    Thread.Sleep(10);
                }

                //剩余的字节大于0
                if (remaind > 0)
                {
                    //此时pagenum=2,则剩余的(2*4096即8192开始取剩余的字节个数)
                    serialPort1.Write(data, (pagenum * 4096), remaind);
                }


            }
            catch (Exception ex)
            {
                MessageBox.Show("发送数据失败" + ex.Message.ToString(),"错误");
            }

        }
    }
}
